/* LEDC (LED Controller) fade example

   This example code is in the Public Domain (or CC0 licensed, at your option.)

   Unless required by applicable law or agreed to in writing, this
   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
   CONDITIONS OF ANY KIND, either express or implied.
*/
#include "driver/ledc.h"
#include "esp_err.h"
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
#include "freertos/task.h"
#include <stdio.h>

/*
 * About this example
 *
 * 1. Start with initializing LEDC module:
 *    a. Set the timer of LEDC first, this determines the frequency
 *       and resolution of PWM.
 *    b. Then set the LEDC channel you want to use,
 *       and bind with one of the timers.
 *
 * 2. You need first to install a default fade function,
 *    then you can use fade APIs.
 *
 * 3. You can also set a target duty directly without fading.
 *
 * 4. On ESP32, GPIO18/19/4/5 are used as the LEDC outputs:
 *              GPIO18/19 are from the high speed channel group
 *              GPIO4/5 are from the low speed channel group
 *
 *    On other targets, GPIO8/9/4/5 are used as the LEDC outputs,
 *    and they are all from the low speed channel group.
 *
 * 5. All the LEDC outputs change the duty repeatedly.
 *
 */

#define LEDC_HS_TIMER LEDC_TIMER_0
#define LEDC_HS_MODE LEDC_LOW_SPEED_MODE
#define LEDC_HS_CH0_GPIO (32)
#define LEDC_HS_CH0_CHANNEL LEDC_CHANNEL_0
#define LEDC_HS_CH1_GPIO (33)
#define LEDC_HS_CH1_CHANNEL LEDC_CHANNEL_1
#define LEDC_LS_CH2_GPIO (22)
#define LEDC_LS_CH2_CHANNEL LEDC_CHANNEL_2

#define LEDC_TEST_CH_NUM (3)
#define LEDC_TEST_DUTY (4000)
#define LEDC_TEST_FADE_TIME (2000)
#define DEFAULT_MAX_BRIGHTNESS 8191

const static char *TAG = "test";

// LED枚举
typedef enum {
  LED_BLUE = 0,
  LED_YELLOW,
  LED_WHITE,
  LED_NUM,
  LED_ALL_PAIRS,     // 特殊模式：两两交替 梦幻叠闪
  LED_DREAM_TWINKLE, // 梦幻闪烁
  LED_DREAM_FLASH,   // 梦幻叠闪
} led_mode_t;

ledc_channel_config_t ledc_channel[LEDC_TEST_CH_NUM] = {

    {.channel = LEDC_HS_CH0_CHANNEL,
     .duty = 0,
     .gpio_num = LEDC_HS_CH0_GPIO,
     .speed_mode = LEDC_HS_MODE,
     .hpoint = 0,
     .timer_sel = LEDC_HS_TIMER,
     .flags.output_invert = 0},
    {.channel = LEDC_HS_CH1_CHANNEL,
     .duty = 0,
     .gpio_num = LEDC_HS_CH1_GPIO,
     .speed_mode = LEDC_HS_MODE,
     .hpoint = 0,
     .timer_sel = LEDC_HS_TIMER,
     .flags.output_invert = 0},

    {.channel = LEDC_LS_CH2_CHANNEL,
     .duty = 0,
     .gpio_num = LEDC_LS_CH2_GPIO,
     .speed_mode = LEDC_HS_MODE,
     .hpoint = 0,
     .timer_sel = LEDC_HS_TIMER,
     .flags.output_invert = 0},

};

/*
 * This callback function will be called when fade operation has ended
 * Use callback only if you are aware it is being called inside an ISR
 * Otherwise, you can use a semaphore to unblock tasks
 */
static IRAM_ATTR bool cb_ledc_fade_end_event(const ledc_cb_param_t *param,
                                             void *user_arg) {
  BaseType_t taskAwoken = pdFALSE;

  if (param->event == LEDC_FADE_END_EVT) {
    SemaphoreHandle_t counting_sem = (SemaphoreHandle_t)user_arg;
    xSemaphoreGiveFromISR(counting_sem, &taskAwoken);
  }

  return (taskAwoken == pdTRUE);
}

void power_on(void) {
  ESP_LOGI(TAG, "power on-----");
  // 作为普通gpio
  gpio_config_t io_conf = {
      /*中断使能*/
      .intr_type = GPIO_INTR_DISABLE,
      /*输出模式调节*/
      .mode = GPIO_MODE_OUTPUT,
      /*配置引脚的掩码*/
      // .pin_bit_mask = (1ull << GPIO_NUM_12) | (1ull << LED_BLUETOOTH),
      .pin_bit_mask = (1ull << GPIO_NUM_12),
      /*下拉使能*/
      .pull_down_en = 0,
      /*上拉使能*/
      .pull_up_en = 0,
  };
  gpio_config(&io_conf);
  // 开机
  gpio_set_level(GPIO_NUM_12, 1);
}

// 设置LED亮度
void set_led_brightness(int led_index, uint32_t brightness) {
  if (led_index >= LED_NUM)
    return;

  ledc_set_duty(ledc_channel[led_index].speed_mode,
                ledc_channel[led_index].channel, brightness);
  ledc_update_duty(ledc_channel[led_index].speed_mode,
                   ledc_channel[led_index].channel);
}

void app_main(void) {
  int ch;

  power_on();
  /*
   * Prepare and set configuration of timers
   * that will be used by LED Controller
   */
  ledc_timer_config_t ledc_timer = {
      .duty_resolution = LEDC_TIMER_13_BIT, // resolution of PWM duty
      .freq_hz = 100,                       // frequency of PWM signal
      .speed_mode = LEDC_HS_MODE,           // timer mode
      .timer_num = LEDC_HS_TIMER,           // timer index
      .clk_cfg = LEDC_AUTO_CLK,             // Auto select the source clock
  };
  // Set configuration of timer0 for high speed channels
  ledc_timer_config(&ledc_timer);

  // Prepare and set configuration of timer1 for low speed channels
  ledc_timer.speed_mode = LEDC_HS_MODE;
  ledc_timer.timer_num = LEDC_HS_TIMER;
  ledc_timer_config(&ledc_timer);

  // Set LED Controller with previously prepared configuration
  for (ch = 0; ch < LEDC_TEST_CH_NUM; ch++) {
    ledc_channel_config(&ledc_channel[ch]);
  }

  // Initialize fade service.
  ledc_fade_func_install(0);
  ledc_cbs_t callbacks = {.fade_cb = cb_ledc_fade_end_event};
  SemaphoreHandle_t counting_sem =
      xSemaphoreCreateCounting(LEDC_TEST_CH_NUM, 0);

  for (ch = 0; ch < LEDC_TEST_CH_NUM; ch++) {
    ledc_cb_register(ledc_channel[0].speed_mode, ledc_channel[0].channel,
                     &callbacks, (void *)counting_sem);
  }

  while (1) {

    // 白 蓝 黄依次长亮
    // printf("1. 依次长亮\n");
    // set_led_brightness(LED_WHITE, DEFAULT_MAX_BRIGHTNESS / 2);
    // set_led_brightness(LED_BLUE, 0);
    // set_led_brightness(LED_YELLOW, 0);
    // vTaskDelay(1000 / portTICK_PERIOD_MS);
    // set_led_brightness(LED_BLUE, DEFAULT_MAX_BRIGHTNESS / 2);
    // set_led_brightness(LED_WHITE, 0);
    // set_led_brightness(LED_YELLOW, 0);
    // vTaskDelay(1000 / portTICK_PERIOD_MS);
    // set_led_brightness(LED_YELLOW, DEFAULT_MAX_BRIGHTNESS / 2);
    // set_led_brightness(LED_WHITE, 0);
    // set_led_brightness(LED_BLUE, 0);
    // vTaskDelay(1000 / portTICK_PERIOD_MS);
    // set_led_brightness(LED_YELLOW, 0);
    // set_led_brightness(LED_WHITE, 0);
    // set_led_brightness(LED_BLUE, 0);

    printf("2. 梦幻闪烁 = %d\n", LEDC_TEST_DUTY);
    for (int i = 0; i < LED_NUM; i++) {
      ledc_set_fade_with_time(ledc_channel[i].speed_mode,
                              ledc_channel[i].channel, LEDC_TEST_DUTY,
                              LEDC_TEST_FADE_TIME);
      ledc_fade_start(ledc_channel[i].speed_mode, ledc_channel[i].channel,
                      LEDC_FADE_NO_WAIT);

      ledc_set_fade_with_time(ledc_channel[i].speed_mode,
                              ledc_channel[i].channel, 0, LEDC_TEST_FADE_TIME);
      ledc_fade_start(ledc_channel[i].speed_mode, ledc_channel[i].channel,
                      LEDC_FADE_NO_WAIT);

    }
    // for (int i = 0; i < LEDC_TEST_CH_NUM; i++) {
    //     xSemaphoreTake(counting_sem, portMAX_DELAY);
    //   }
    // vTaskDelay(1000 / portTICK_PERIOD_MS);


    

    printf("3. 梦幻叠闪\n");
    // for (ch = 0; ch < LEDC_TEST_CH_NUM; ch++) {
    //   ledc_set_fade_with_time(ledc_channel[ch].speed_mode,
    //                           ledc_channel[ch].channel, 0, LEDC_TEST_FADE_TIME);
    //   ledc_fade_start(ledc_channel[ch].speed_mode, ledc_channel[ch].channel,
    //                   LEDC_FADE_NO_WAIT);
    // }

    // for (int i = 0; i < LEDC_TEST_CH_NUM; i++) {
    //   xSemaphoreTake(counting_sem, portMAX_DELAY);
    // }

    // printf("3. LEDC set duty = %d without fade\n", LEDC_TEST_DUTY);
    // for (ch = 0; ch < LEDC_TEST_CH_NUM; ch++) {
    //     ledc_set_duty(ledc_channel[ch].speed_mode, ledc_channel[ch].channel,
    //     LEDC_TEST_DUTY); ledc_update_duty(ledc_channel[ch].speed_mode,
    //     ledc_channel[ch].channel);
    // }
    // vTaskDelay(1000 / portTICK_PERIOD_MS);

    // printf("4. LEDC set duty = 0 without fade\n");
    // for (ch = 0; ch < LEDC_TEST_CH_NUM; ch++) {
    //     ledc_set_duty(ledc_channel[ch].speed_mode, ledc_channel[ch].channel,
    //     0); ledc_update_duty(ledc_channel[ch].speed_mode,
    //     ledc_channel[ch].channel);
    // }
    vTaskDelay(1000 / portTICK_PERIOD_MS);
  }
}
